package com.example.animdemo.render;

import static javax.microedition.khronos.opengles.GL10.GL_FLOAT;
import static javax.microedition.khronos.opengles.GL10.GL_REPEAT;
import static javax.microedition.khronos.opengles.GL10.GL_TEXTURE_2D;
import static javax.microedition.khronos.opengles.GL10.GL_TEXTURE_COORD_ARRAY;
import static javax.microedition.khronos.opengles.GL10.GL_TEXTURE_WRAP_S;
import static javax.microedition.khronos.opengles.GL10.GL_TEXTURE_WRAP_T;
import static javax.microedition.khronos.opengles.GL10.GL_TRIANGLE_STRIP;
import static javax.microedition.khronos.opengles.GL10.GL_VERTEX_ARRAY;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

import com.example.animdemo.base.DebugLog;

public class QuadBitmap extends DrawableObject {

	private FloatBuffer mVertices;
    private FloatBuffer mCoordinates;
//    private ShortBuffer mIndices;
    
    private boolean mDirtyVertice;
    private boolean mDirtyTexCoord;

    private Texture mTexture;
    private int mCropX;
    private int mCropY;
    private int mCropW;
    private int mCropH;
    private boolean mFlipX;
    private boolean mFlipY;
    
    private float mAnchorX;
    private float mAnchorY;
    
    private float mScaleX;
    private float mScaleY;
    
    private float mRotation;
    
    public boolean visible = true;
    
    //-------------------------------------------------------
    // getter, setter
    
    public final int getCropX() {
		return mCropX;
	}
    public final int getCropY() {
		return mCropY;
	}
    public final int getCropW() {
		return mCropW;
	}
    public final int getCropH() {
		return mCropH;
	}
    public final float getScaleX() {
		return mScaleX;
	}
    public final float getScaleY() {
		return mScaleY;
	}
    public final float getAnchorX() {
		return mAnchorX;
	}
    public final float getAnchorY() {
		return mAnchorY;
	}
    public final float getRotation() {
		return mRotation;
	}
    
    public final void setScale(float scaleX, float scaleY) {
//    	mDirtyTexCoord = (mFlipX != scaleX<0) ||(mFlipY != scaleY<0);
//    	mFlipX = scaleX<0;
//    	mFlipY = scaleY<0;
//    	
//    	scaleX = Math.abs(scaleX);
//    	scaleY = Math.abs(scaleY);
//    	mDirtyVertice = (this.mScaleX != scaleX || this.mScaleY != scaleY);
    	this.mScaleX = scaleX;
    	this.mScaleY = scaleY;
    }
    public final void setAnchor(float anchor) {
    	mDirtyVertice |= (this.mAnchorX != anchor ||  this.mAnchorY != anchor);
		this.mAnchorX = this.mAnchorY = anchor; 
	}
    public final void setAnchor(float anchorX, float anchorY) {
    	mDirtyVertice |= (this.mAnchorX != anchorX ||  this.mAnchorY != anchorY);
		this.mAnchorX = anchorX;
		this.mAnchorY = anchorY;
	}
	public final void setCropTex(int cropX, int cropY, int cropW, int cropH) {
		mDirtyTexCoord |= (mCropX != cropX || mCropY != cropY || mCropW != cropW || mCropH != cropH);
		mCropX = cropX;
    	mCropY = cropY;
    	mCropW = cropW;
    	mCropH = cropH;
	}
    public final void setRotation(float rotation) {
		this.mRotation = rotation;
	}
	
    //-------------------------------------------------------
    // constructor
    
    public QuadBitmap() {
    	ByteBuffer vfb = ByteBuffer.allocateDirect(4 * 2 * 4);
        vfb.order(ByteOrder.nativeOrder());
        mVertices = vfb.asFloatBuffer();

        ByteBuffer tfb = ByteBuffer.allocateDirect(4 * 2 * 4);
        tfb.order(ByteOrder.nativeOrder());
        mCoordinates = tfb.asFloatBuffer();
    }
    
    public static final QuadBitmap drawableTextureWith(Texture texture, int cropX, int cropY, int cropW, int cropH, 
    		float anchorX, float anchorY, float scaleX, float scaleY) {
    	return new QuadBitmap().initWith(texture, cropX, cropY, cropW, cropH, anchorX, anchorY, scaleX, scaleY);
    }
        
    public static final QuadBitmap drawableTextureWith(Texture texture, 
    		float anchor, float scale) {
    	return new QuadBitmap().initWith(texture, 0, 0, texture.width, texture.height, anchor, anchor, scale, scale);
    }
    
    public static final QuadBitmap drawableTextureWith(Texture texture) {
    	return new QuadBitmap().initWith(texture, 0, 0, texture.width, texture.height, 0.5f, 0.5f, 1, 1);
    }
   
    //--------------------------------------------------------
    // setup
    
    public final QuadBitmap initWith(Texture texture, int cropX, int cropY, int cropW, int cropH, 
    		float anchorX, float anchorY, float scaleX, float scaleY) {
    	mTexture = texture;
    	mCropX = cropX;
    	mCropY = cropY;
    	mCropW = cropW;
    	mCropH = cropH;
    	mScaleX = Math.abs(scaleX);
    	mScaleY = Math.abs(scaleY);
    	mAnchorX = anchorX;
    	mAnchorY = anchorY;
    	mDirtyVertice = true;
    	mDirtyTexCoord = true;
    	mFlipX = scaleX<0;
    	mFlipY = scaleY<0;
    	
        updateVertex();
        updateTexCoord();
        return this;
    }
    
    private final void updateVertex()
    {
    	if(mTexture.loaded) {
	    	final float minX = -mCropW*mAnchorX;
	    	final float minY = -mCropH*mAnchorY;
	    	final float maxX = mCropW + minX;
			final float maxY = mCropH + minY;
			float vertices[] = {minX, minY, 
	                maxX, minY,
	                minX, maxY,
	                maxX, maxY};
	        mVertices.put(vertices);
	        mVertices.position(0);
	        
	        DebugLog.d("AminDemo", "vertex" + "(" + minX + ";" + maxX + ")(" + minY + "," + maxY + ")");
	        
	        mDirtyVertice = false;
    	}
    }
    
    private final void updateTexCoord() {
    	if(mTexture.loaded) {
	    	final float width = mTexture.width;
			final float height = mTexture.height;
	    	float minS = mCropX / width;
			float minT = mCropY / height;
			float maxS = (mCropX + mCropW) / width;
			float maxT = (mCropY + mCropH) / height;
			
			float coordinates[] = {minS, maxT,
	                maxS, maxT,
	                minS, minT,
	                maxS, minT};
			
			DebugLog.d("AnimDemo", "texcoord" + "("+minS+ " "+maxS +") ("+ minT +","+ maxT +")");
			
	        mCoordinates.put(coordinates);
	        mCoordinates.position(0);
	        mDirtyTexCoord = false;
    	}
    }
    
    public void reset() {
        mTexture = null;
    }
    
    //-------------------------------------------------------
    // draw
    
	@Override
	public void draw(float x, float y, float scaleX, float scaleY) {
		if (mTexture.loaded) {
			if (mDirtyVertice) 
				updateVertex();
			if (mDirtyTexCoord) 
				updateTexCoord();
			
			GL10 gl = OpenGLSystem.getGL();
			final Texture texture = mTexture;

			gl.glEnable(GL_TEXTURE_2D);
//			OpenGLSystem.bindTexture(GL10.GL_TEXTURE_2D, texture.name);

			gl.glEnableClientState(GL_VERTEX_ARRAY);
			gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY);

			gl.glBindTexture(GL_TEXTURE_2D, texture.name);

			gl.glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
			gl.glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

			gl.glVertexPointer(2, GL_FLOAT, 0, mVertices);
			gl.glTexCoordPointer(2, GL_FLOAT, 0, mCoordinates);

			// Transform
			gl.glPushMatrix();
			gl.glTranslatef(x*scaleX, y*scaleY, 0);
			if (mRotation != 0)
				gl.glRotatef(mRotation*180f/(float)Math.PI, 0, 0, 1f);
			gl.glScalef(scaleX*mScaleX, scaleY*mScaleY, 0);
			
			gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

			gl.glPopMatrix();

			// Clear the vertex and color arrays
			gl.glDisableClientState(GL_VERTEX_ARRAY);
			gl.glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		}
	}
}
